package fr.aura.launcher.client;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import org.apache.log4j.Logger;

public class LNCClient {
	private Socket mySocket=null;
	private DataInputStream in = null;
	private DataOutputStream out = null;
	private boolean connected = false;
	private static String buildversion = "Java Client V1.00";
	static Logger logger = Logger.getLogger(LNCClient.class.getName());
	
	private LNCSrvAckMsg receiveAck() {
		logger.debug("receiveAck begin");
		LNCSrvAckMsg msg = new LNCSrvAckMsg();
		if (in!=null) {
			byte header[] = new byte[msg.getHdr().getByteSize()];
			try {
				in.read(header,0,msg.getHdr().getByteSize());
				msg.getHdr().fromByteArray(header);
				int msgSize = msg.getHdr().getlSize();
				byte fullBuffer[] = new byte[header.length+msgSize];
				System.arraycopy(header, 0, fullBuffer, 0, header.length);
				in.read(fullBuffer,header.length,msgSize);
				msg.fromByteArray(fullBuffer);
			} catch (IOException e) {
				logger.error(e);
			}
		}
		logger.debug("receiveAck end");
		return msg;	
	}
	
	//LNCOPEN, throws exception if error
	public int LNCOPEN(String server, int portNumber) {
		logger.debug("LNCOPEN begin, server:"+server+" port:"+portNumber);
		//if already connected, do nothing
		if (connected == true) {
			logger.debug("LNCOPEN end");
			return -1;
		}
		
		try {
			mySocket = new Socket(server,portNumber);
		} catch (UnknownHostException e) {
			connected = false;
			logger.error(e);
			logger.debug("LNCOPEN end");
			return -1;
		} catch (IOException e) {
			connected = false;
			logger.error(e);
			logger.debug("LNCOPEN end");
			return -1;
		}
		
		try {
			in = new DataInputStream(mySocket.getInputStream());
			out = new DataOutputStream(mySocket.getOutputStream());
			connected = true;
			
			//handle licence handshake
			LNCSrvCnxMsg msg = new LNCSrvCnxMsg();
			byte header[] = new byte[msg.getByteSize()];
			in.read(header, 0, msg.getByteSize());
			msg.fromByteArray(header);
					
			LNCSrvMsg response = new LNCSrvMsg();
			response.setCmd("LICACK");
			response.setOption("5467");
			
			response.setParm1("LAUNCHERGATEWAY;LICID=1;CCSID=0;BUILT="+buildversion);
			byte tmpArray[] = response.toByteArray();
			out.write(tmpArray);
		
			out.flush();
			LNCSrvAckMsg ackmsg = receiveAck();
			String ackCode = ackmsg.getAckCode();
			ackCode = ackCode.trim();
			
			if (ackCode.compareToIgnoreCase("*ACK")!=0 && !ackCode.isEmpty()) {
				logger.error("No ACK received, got '"+ackmsg.getAckCode()+"' instead");
				connected = false;
				logger.debug("LNCOPEN end");
				return -1;
			}
			
			LNCSrvMsg property = new LNCSrvMsg();
			property.setCmd("PROPERTY");
					
			property.setParm1("LittleEndian=True;ASCII=True");
			tmpArray = property.toByteArray();
			out.write(tmpArray);
		
			out.flush();
			ackmsg = receiveAck();
			ackCode = ackmsg.getAckCode();
			ackCode = ackCode.trim();
			if (ackCode.compareToIgnoreCase("*ACK")!=0 && !ackCode.isEmpty()) {
				connected=false;
				logger.error("No ACK received, got '"+ackmsg.getAckCode()+"' instead");
				logger.debug("LNCOPEN end");
				return -1;
			}
		} catch (IOException e) {
			connected = false;
			logger.error(e);
			logger.debug("LNCOPEN end");
			return -1;
		}
		logger.debug("LNCOPEN end");
		return 0;
	}
	
	
	public void LNCCLOSE() {
		logger.debug("LNCCLOSE begin");
		try {
			in.close();
			out.flush();
			out.close();
			mySocket.close();
			connected=false;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			logger.error(e);
			connected=false;
		}
		logger.debug("LNCCLOSE end");
	}
	
	public LNCSrvAckMsg LNCCMD(String pVerb, String pOption, String pParm1, String pParm2) throws LauncherException{
		LNCSrvAckMsg ackmsg = null;
		logger.debug("LNCCMD begin verb: "+pVerb+ " option:"+pOption+" parm1:"+pParm1+" "+pParm2);
		
		if (!connected) {
			logger.error("Not connected to Launcher Server, please run LNCOPEN first");
			logger.debug("LNCCMD end");
			throw new LauncherException("Not connected to Launcher Server, please run LNCOPEN first.");
		}
		if (pVerb == null) {
			logger.error("Cannot run LNCCMD without a verb.");
			logger.debug("LNCCMD end");
			throw new LauncherException("Cannot run LNCCMD without a verb.");
		}
		LNCSrvMsg cmd = new LNCSrvMsg();
		cmd.setCmd(pVerb);
		if (pOption != null) {
			cmd.setOption(pOption);
		}
		if (pParm1 != null) {
			cmd.setParm1(pParm1);
		}
		if (pParm2 != null) {
			cmd.setParm2(pParm2);
		}
		byte [] tmpArray = cmd.toByteArray();
		try {
			out.write(tmpArray);
			out.flush();
			ackmsg = receiveAck();
		} catch (IOException e) {
			logger.error("I/O Exception in LNCCMD()."+e.getLocalizedMessage());
			logger.debug("LNCCMD end");
			throw new LauncherException("I/O exception");
		}
		logger.debug("LNCCMD end");
		return ackmsg;
	}
	
	
}
